/* em/builtin.c 
 * 
 * This file is part of em. 
 * 
 * em is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * em is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with em. If not, see <https://www.gnu.org/licenses/>
 */ 




#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <em/em.h>


int do_builtin_add(struct word *w);

struct builtin_macro {
	char 		*name;
	int  		(* do_builtin) (struct word *w);
	int 		len;
} builtins[] = {
	{ "+", do_builtin_add, 1 }, 
	{ NULL, NULL, 0 }
};

int builtin(struct word *w) {
	struct builtin_macro *p;
	
	for (p = builtins; p->name; p++) 
		/* i think using 'w->len' is faster than using p->len, 
		 * the first one is in cache. */

		if (!strncmp(p->name, w->p, w->len) && w->len == p->len) {
			p->do_builtin(w);
			return 1;
		}
	
	return 0;
}


int do_builtin_add(struct word *word) {
	struct klist_node 	*n;
	struct word 		*w, *a, *b;
	long 			res;
	char 			s[32];

	n = &(w = word)->node;
	a = word_of(n->prev);
	b = word_of(n->next);

	if (a->type != WORD_DIGIT || b->type != WORD_DIGIT) {
		fprintf(stderr, "builtin_add: wrong type: both side must be a digit. \n");
		abort();
	}

	res = getnumber(a) + getnumber(b);
	sprintf(s, "%ld ", res);
	outputs(s);

	mark_word(a);
	mark_word(b);

	output_remove(a);

	return 0;
}

